package xyz.heyaoshare.core.service.system.impl;

import com.mybatisflex.core.query.QueryChain;
import com.mybatisflex.core.update.UpdateChain;
import com.mybatisflex.spring.service.impl.CacheableServiceImpl;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import xyz.heyaoshare.common.constants.CacheKey;
import xyz.heyaoshare.config.satoken.utils.AuthUtils;
import xyz.heyaoshare.core.controller.system.menu.vo.req.*;
import xyz.heyaoshare.core.controller.system.menu.vo.resp.MenuDetailRespVO;
import xyz.heyaoshare.core.controller.system.menu.vo.resp.MenuTreeRespVO;
import xyz.heyaoshare.core.entity.system.Menu;
import xyz.heyaoshare.core.entity.system.RoleMenu;
import xyz.heyaoshare.core.entity.system.User;
import xyz.heyaoshare.core.enums.system.menu.MenuOpenStyleEnum;
import xyz.heyaoshare.core.enums.system.menu.MenuStatusEnum;
import xyz.heyaoshare.core.enums.system.menu.MenuTypeEnum;
import xyz.heyaoshare.core.enums.system.user.SuperAdminEnum;
import xyz.heyaoshare.core.mapper.system.MenuMapper;
import xyz.heyaoshare.core.service.system.MenuService;
import xyz.heyaoshare.utils.BeanUtils;
import xyz.heyaoshare.utils.TreeUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

import static xyz.heyaoshare.exceptions.code.ErrorInfo.*;
import static xyz.heyaoshare.exceptions.customize.ServerException.exception;

/**
 * 菜单 Service 实现类
 * @author YueHe
 * @version 0.0.1
 * @since 2025/6/25 下午2:06
 */
@Slf4j
@Service
@CacheConfig(cacheNames = CacheKey.MENU_SERVICE)
public class MenuServiceImpl extends CacheableServiceImpl<MenuMapper, Menu> implements MenuService {

    @Resource
    private AuthUtils authUtils;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean insert(MenuInsertReqVO reqVO) {
        Menu menu = BeanUtils.copyProperties(reqVO, Menu.class);
        menu.setStatus(MenuStatusEnum.ENABLE.getValue()).setOpenStyle(MenuOpenStyleEnum.EXTERNAL.getValue());

        try {
            this.mapper.insert(menu);
            return Boolean.TRUE;
        } catch (Exception e) {
            log.error("新增菜单失败", e);
            throw exception(INSERT_MENU_FAILED);
        }
    }


    @Override
    public List<MenuTreeRespVO> selectTreeList(MenuListReqVO reqVO) {
        User user = authUtils.getUser();
        List<Menu> menus = new ArrayList<>();
        if (user.getIsAdmin() == SuperAdminEnum.YES.getValue()) {
            menus = QueryChain.of(this.mapper).eq(Menu::getStatus, MenuStatusEnum.ENABLE.getValue()).list();
        }
        if (user.getIsAdmin() == SuperAdminEnum.NO.getValue()) {
            menus = this.mapper.selectListByUserId(user.getId());
        }
        return TreeUtils.buildMenuTree(menus);
    }

    @Override
    public MenuDetailRespVO selectDetail(MenuDetailReqVO reqVO) {
        Menu menu = QueryChain.of(this.mapper).eq(Menu::getId, reqVO.getId()).one();
        if (menu == null) throw exception(MENU_NOT_EXIST);

        return BeanUtils.copyProperties(menu, MenuDetailRespVO.class)
                .setTypeStr(MenuTypeEnum.getLabel(menu.getType()))
                .setOpenStyleStr(MenuOpenStyleEnum.getLabel(menu.getOpenStyle()))
                .setStatusStr(MenuStatusEnum.getLabel(menu.getStatus()));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean delete(MenuDeleteReqVO reqVO) {

        try {
            // 1.删除菜单信息
            UpdateChain.of(this.mapper).eq(Menu::getId, reqVO.getMenuId()).remove();
        } catch (Exception e) {
            log.error("删除菜单失败", e);
            throw exception(DELETE_MENU_FAILED);
        }

        try {
            // 2.删除角色菜单关联信息
            UpdateChain.of(RoleMenu.class).eq(RoleMenu::getMenuId, reqVO.getMenuId()).remove();
        } catch (Exception e) {
            log.error("删除角色菜单关联信息失败", e);
            throw exception(DELETE_ROLE_MENU_REL_FAILED);
        }

        return Boolean.TRUE;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean updateData(MenuUpdateReqVO reqVO) {
        if (reqVO.getParentId() != null && Objects.equals(reqVO.getId(), reqVO.getParentId())) {
            throw exception(MENU_PARENT_IS_SELF);
        }

        try {
            UpdateChain.of(this.mapper)
                    .set(Menu::getName, reqVO.getName())
                    .set(Menu::getParentId, reqVO.getParentId())
                    .set(Menu::getSort, reqVO.getSort())
                    .set(Menu::getUrl, reqVO.getUrl())
                    .set(Menu::getAuthority, reqVO.getAuthority())
                    .set(Menu::getIcon, reqVO.getIcon())
                    .eq(Menu::getId, reqVO.getId())
                    .update();
            return Boolean.TRUE;
        } catch (Exception e) {
            log.error("更新菜单失败", e);
            throw exception(UPDATE_MENU_FAILED);
        }
    }

}